# -*- coding: utf-8 -*-
"""
功能描述：
此文件中处理了银企对接的接口实现，将企业的交易记录，支付业务与银行接口打通
时间：2020年9月
版本：V1.0
作者：lisheng

"""
import configparser
import os

import pymongo
import pymysql
import logging.config
import requests
import json
import time

import xmltodict

# from celery import Celery


# cel = Celery()

cf = configparser.ConfigParser()
cf.read('config\dbconfig.ini', encoding='utf-8')
#
# mondbclient = pymongo.MongoClient(host=cf.get('mongodb', 'DB_HOST'), port=int(cf.get('mongodb', 'DB_PORT')),
#                                   username=cf.get('mongodb', 'DB_USER'), password=cf.get('mongodb', 'DB_PWD'))
#


url = cf.get('cmb', 'URL')


# 银行接口查询类生成
def querytransaction(strStartDate, strEndDate, FunName, Account,
                     BranchBankNum, BankCode, LoginName):
    """
    查询银行交易记录：根据FunName来区分业务类型，转换成XML查询我们的，调用接口，处理接口反馈形成LIST，
    :param strStartDate：交易开始日期
    :param strEndDate: 交易结束日期
    :param FunName: 交易业务类型
        {"2.3.查询账户交易信息"："GetTransInfo",
        "2.8.查询电子回单信息（保存图片）":"SDKCSFDFBRTIMG"}
    :param Account: 银行帐号
    :param BranchBankNum:分行代码 eg.招商深圳行 75
    :param BankCode: 银行代号 ，用于标识是哪家银行，以下是一些银行的简码
        {"PSBC": '中国邮政储蓄银行', "ICBC": '工商银行', "ABC": '农业银行', "BOC": '中国银行', "CCB": '建设银行',
        "COMM": '交通银行', "CITIC": '中信银行', "CEB": '光大银行', "CMBC": '民生银行',"GDB": '广发银行', "SPDB": "浦东发展银行",
        "CMB": '招商银行', "CIB": '兴业银行',"CZBANK": '浙商银行', "BOHAIB": '渤海银行', "SPABANK": '平安银行'}

    :param LoginName: 登陆帐户名
    :return  返回查询的出来的交易记录，交易记录以List方式存储，每条明细以字典方式保存
    """
    # 根据BankCode和FunName值来组织不同的JSON对象
    transjson = {}  # 构建交易查询对象
    if BankCode == "CMB":  # 招商银行
        if FunName == "GetTransInfo":  # 2.3.查询账户交易信息
            info = {}  # 查询交易头，TODO:未来可以考虑统一处理，每个银行包装一个消息头
            sdktsinfx = {}  # 查询交易体
            info.update({"FUNNAM": FunName, "DATTYP": 2, "LGNNAM": LoginName})
            sdktsinfx.update({"BBKNBR": BranchBankNum, "ACCNBR": Account,
                              "BGNDAT": strStartDate, "ENDDAT": strEndDate})
            transjson.update({"INFO": info, "SDKTSINFX": sdktsinfx})
        if FunName == "SDKCSFDFBRTIMG":  # 2.8.查询电子回单信息（保存图片）
            info = {}  # 查询交易头，TODO:未来可以考虑统一处理，每个银行包装一个消息头
            csrrcfdfy0 = {}  # 查询交易体
            info.update({"FUNNAM": FunName, "DATTYP": 2, "LGNNAM": LoginName})
            csrrcfdfy0.update({"EACNBR": Account, "BEGDAT": strStartDate, "ENDDAT": strEndDate, "RRCFLG": "1"})
            transjson.update({"INFO": info, "CSRRCFDFY0": csrrcfdfy0})

    if BankCode == "CEB":  # 光大银行
        if FunName == "GetTransInfo":  # 2.3.查询账户交易信息
            pass
        if FunName == "SDKCSFDFBRTIMG":  # 2.8.查询电子回单信息（保存图片）
            pass
        pass

    xmlstring = json_to_xml(transjson)

    try:
        resultxml = post_service(xmlstring.encode("GBK"))
        logging.info("回单数据生成成功！执行SQL语句为：%s" % resultxml)
    except Exception as err:
        logging.exception("插入错误,错误代码：%s，执行的SQL语句为%s" % (err, resultxml))

    return ParseXMLToDict(resultxml)


# 银行接口付款交易类生成
def paymenttransaction():
    """

    :return:
    """
    pass


# 同步银行信息到综合平台接口
def createBizInfData(transList, OwnerID):
    """
    创建综合业务系统银行交易接口数据.
    将其实同步到综合业务平台接口表。
    :param transList: 整理过的交易记录以LIST{DICT},列表+字典的方式传递
    :return:
    """
    govdb = pymysql.connect(cf.get('mysql', 'DB_HOST'), cf.get('mysql', 'DB_USER'),
                            cf.get('mysql', 'DB_PWD'), cf.get('mysql', 'DB_NAME'))
    cr = govdb.cursor()

    totalvalues = ""
    f1 = ""
    for item1 in transList:
        k, v = item1.popitem()
        if k == "INFO":
            if v['RETCOD'] == '0':
                continue
            else:
                break
        f1 = ""
        v1 = ""
        for i in v:
            f1 = f1 + i + ","
            if v[i] is None:
                v1 = v1 + "'',"
                continue
            if type(v[i]) == str:
                if '.' in v[i]:
                    v1 = v1 + str.replace(v[i], ',', '') + ','
                else:
                    v1 = v1 + "'" + v[i] + "',"
                continue

        # totalvalues = totalvalues + "(" + v1[0:len(v1) - 1] + "),"
        strinsertsql = "insert into T_LPROMIS_JKGL_YHJYSJJK (" + f1[0:len(f1) - 1] + ",ownerid,id) value" + \
                       v1[0:len(v1)] + "'" + OwnerID + "','" + v[
                           'REFNBR'] + "') ON DUPLICATE KEY UPDATE AMTCDR=VALUES(AMTCDR)"
        try:
            cr.execute(strinsertsql)
            logging.info("回单数据生成成功！执行SQL语句为：%s" % (strinsertsql))
            govdb.commit()
        except Exception as err:
            logging.exception("插入错误,错误代码：%s，执行的SQL语句为%s" % (err, strinsertsql))

    govdb.close()


# json转xml函数
def json_to_xml(json_str):
    # xmltodict库的unparse()json转xml
    # 参数pretty 是格式化xml
    xml_str = xmltodict.unparse(json_str, pretty=1)
    return xml_str


# 初始化日志配置
def init_logging(default_path="cmbbankconfig.json", default_level=logging.INFO, env_key="LOG_CFG"):
    """
    初始化日志记录的参数
    把日志记录的参数写入到配置文件中。
    配置文件的目录 为Config/logconfig.json
    产生的Log文件，放入至Logs目录中
    """
    path = default_path
    value = os.getenv(env_key, None)
    if value:
        path = value
    if os.path.exists(path):
        with open(path, "r", encoding='utf-8') as f:
            config = json.load(f)
            logging.config.dictConfig(config)
    else:
        logging.basicConfig(level=default_level)


# 工具方法，XML转换至字典
def ParseXMLToDict(strXml):
    """
    将XML处理成字典列表，用于处理银行接口调用后的反馈的XML结果
    :param strXml:
    :return:
    """
    xmlparse = xmltodict.parse(strXml)
    jsonstr = json.dumps(xmlparse, indent=1)
    print(jsonstr)
    decode_json = json.loads(jsonstr)
    retdict = decode_json["CMBSDKPGK"]  # CMBSDKPGK，招行的关键字
    dictlist = []
    for item in retdict:
        if type(retdict[item]) == dict:
            dictlist.append({item: retdict[item]})
        if type(retdict[item]) == list:
            for i in retdict[item]:
                dictlist.append({item: i})
    return dictlist


# 工具方法,提交银行接口，处理HTTP请求
def post_service(strurl, xml_str):
    """
    调用写入业务数据服务方法
    :param strurl: 银行前置机的地址（配置文件中取出）
    :param xml_str:XML格式的提交数据
    :return:
    """
    body_buider = xml_str

    urlString = strurl
    print(urlString)
    postrespond = requests.post(urlString, data=body_buider)
    print(postrespond)
    if postrespond.status_code != 200:
        raise Exception("post error status_code != 200")
    # buidler = json.loads(postrespond.text)
    return postrespond.text


if __name__ == '__main__':
    # 初始化日记的记录文件配置
    init_logging(default_path="config//cmbbankconfig.json")
    logging.info('系统开始运行')

    # 每个公司，针对每个银行都会有一个银行帐号，将其组织到配置文件中，系统将进行自动循环调用。
    companylist = {}  # 公司帐号列表
    configfilepath = 'config//companylist.json'  # 配置文件的路径
    with open(configfilepath, 'r', encoding='utf-8') as f:  # 读取配置文件信息
        companylist = json.load(f)

    # 读取配置文件中列出的需要读取银行清单，逐行去取对就原银行交易数据记录
    # 读取后将其写入综合系统的接口数据中
    for it in companylist['items']:
        # ============================================
        # 1-初始化参数值
        # ============================================
        strStartDate = time.strftime('%Y%m%d')  # 查询开始日期，只取当天的日期,节假日照常运行
        strEndDate = time.strftime('%Y%m%d')  # 查询结束日期，只取当天的日期，节假日照常运行
        strAccount = it['Account']  # 银行帐号
        strBranchBankNum = it['BranchBankNum']  # 分行代码
        strBankCode = it['BankCode']  # 银行标识
        strLoginName = it['logname']  # 银行代号 eg.招行CMB
        strOwnerID = it['companyID']  # 公司编码，CMS系统中的公司编码

        # ============================================
        # 2-处理交易调用
        # ============================================

        # 调用银行查询接口，查询交易记录
        # TODO：在这里可以通过"BankCode":"CMB"值去判断应该调用哪家银行的查询接口，
        #  或者传querytransacion方法，由方法内部来判断执行，需要等多家银行接入后再重构此方法
        strFunName = "GetTransInfo"  # 查询交易流水业务，此业务名称为招银的业务名称，未来其它银行的业务可能会有区别要考虑处理方法
        resultlist = querytransaction(strStartDate, strEndDate, strFunName, strAccount,
                                      strBranchBankNum, strBankCode, strLoginName)
        # 将查询结果写入综合业务系统接口表中
        createBizInfData(resultlist, strOwnerID)

        # 调用银行查询接口，查询电子回单记录
        # 电子回单文件会存放在银行前置机指定的目录中
        # 因此，在银行前置上会有一个监控程序处理银行指定目录，进行文件的上传，更新记录等处理。另外模块来处理。
        # TODO：在这里可以通过"BankCode":"CMB"值去判断应该调用哪家银行的查询接口，
        #  或者传querytransacion方法，由方法内部来判断执行，需要等多家银行接入后再重构此方法
        strFunName = "SDKCSFDFBRTIMG"  # 查询业务电子回单业务，此业务名称为招银的业务名称，未来其它银行的业务可能会有区别要考虑处理方法
        resultlist = querytransaction(strStartDate, strEndDate, strFunName, strAccount,
                                      strBranchBankNum, strBankCode, strLoginName)
